#include<iostream>
#include<unistd.h>
#include<sys/wait.h>
#include<sys/types.h>

#define N 5

using namespace std;

//使用wait等待一个进程
// int main()
// {

//     pid_t id = fork();

//     if(id == 0)
//     {
//         //child
//         int cnt = 5;
//         while(cnt)
//         {
//             cout << "I am child, pid: " << getpid() << endl;
//             cnt--;
//             sleep(1);
//         }

//         exit(0);
//     }
//     else
//     {
//         //father
//         int cnt = 10;
//         while(cnt)
//         {
//             cout << "I am father, pid: " << getpid() << endl;
//             cnt--;
//             sleep(1);
//         }
//     }

//     //父子进程代码共享区
//     //wait是等待任意一个子进程退出
//     pid_t ret = wait(nullptr);
//     if(ret == id)
//     {
//         cout << "wait success..." << endl;
//     }

//     sleep(5);

//     return 0;
// }

//使用wait等待多个进程
// void runchild()
// {
//     int cnt = 5;

//     while(cnt--)
//     {
//         cout << "I am child, pid:" << getpid() << endl;
//         sleep(1);
//     }
// }

// int main()
// {
//     for(int i = 0; i < N; i++)
//     {
//         pid_t id = fork();
//         if(id == 0)
//         {
//             runchild();
//             exit(0);
//         }

//         cout << "process create success..." << endl;
//     }

//     sleep(5);

//     for(int i = 0; i < N; i++)
//     {
//         pid_t ret = wait(nullptr);
//         if(ret > 0)
//         {
//             cout << "wait success..." << endl;
//         }
//     }

//     return 0;
// }

//waitpid可以查看子进程的退出信息
// int main()
// {
//     pid_t id = fork();

//     if(id == 0)
//     {
//         int cnt = 5;
//         while(cnt)
//         {
//             cout << "I am child, pid: " << getpid() << endl;
//             cnt--;
//             sleep(1);
//         }
        
//         int a = 1;
//         a /= 0;

//         exit(0);
//     }
//     else
//     {
//         int cnt = 10;
//         while(cnt)
//         {
//             cout << "I am father, pid: " << getpid() << endl;
//             cnt--;
//             sleep(1);
//         }
//     }

//     int status;
//     //设置成为0应该是表示阻塞式等待
//     pid_t ret = waitpid(-1, &status, 0);
//     if(ret > 0)
//     {
//         cout << "wait success..." << endl;

//         if(WIFEXITED(status))
//         {
//             cout << "程序是正常跑完" << endl;
//         }
//         else
//         {
//             cout << "程序是异常跑完" << endl;
//         }
//     }

//     return 0;
// }

//waitpid进行非阻塞轮询式等待
// int main()
// {
//     pid_t id = fork();

//     if(id == 0)
//     {
//         int cnt = 10;
//         while(cnt)
//         {
//             cout << "I am child, pid: " << getpid() << endl;
//             cnt--;
//             sleep(1);
//         }

//         // int* ptr = nullptr;
//         // *ptr = 10;

//         exit(0);
//     }
//     else
//     {
//         int cnt = 5;
//         while(cnt)
//         {
//             cout << "I am father, pid: " << getpid() << endl;
//             cnt--;
//             sleep(1);
//         }
//     }

//     int status = 0;
//     while(true)
//     {
//         pid_t ret = waitpid(-1, &status, WNOHANG);
//         if(ret > 0)
//         {
//             cout << "wait success..." << endl;

//             if(WIFEXITED(status))
//             {
//                 cout << "程序是正常跑完" << endl;
//             }
//             else
//             {
//                 cout << "程序是异常跑完" << endl;
//             }
//         }
//         else if(ret < 0)
//         {
//             cout << "wait failed" << endl;
//             break;
//         }
//         else
//         {
//             // cout << "子程序还没有退出，继续等待" << endl;
//             cout << "paper is sb" << endl;

//             sleep(1);
//         }
//     }

//     sleep(5);
//     return 0;
// }

#define MAX 10

typedef void (*Task)();
Task TaskTable[MAX];

void Task1()
{
    cout << "I am Task1" << endl;
}

void Task2()
{
    cout << "I am Task2" << endl;
}

void Task3()
{
    cout << "I am Task3" << endl;
}

void InitTask()
{
    for(int i = 0; i < MAX; i++)
    {
        TaskTable[i] = nullptr;
    }
}

void AddTask(Task t)
{
    int pos = 0;
    for(; pos < MAX; pos++)
    {
        if(TaskTable[pos] != nullptr)
        {
            continue;
        }
        else
        {
            //这个地方忘记退出了
            break;
        }
    }

    if(pos == MAX)
    {
        cout << "Add failed!" << endl;
        return;
    }

    TaskTable[pos] = t;
}

void ExcuteTask()
{
    for(int i = 0; i < MAX; i++)
    {
        if(TaskTable[i])
        {
            TaskTable[i]();
            sleep(1);
        }
    }
}

void runchild()
{
    int cnt = 10;
    while(cnt--)
    {
        cout << "I am child, pid: " << getpid() << endl;
        sleep(1);
    }
}

int main()
{

    pid_t id = fork();
    if(id == 0)
    {
        runchild();
        exit(0);
    }
    else
    {
        Task t1 = Task1;
        Task t2 = Task2;
        Task t3 = Task3;

        InitTask();
        AddTask(Task1);
        AddTask(Task2);
        AddTask(Task3);

        int cnt = 5;
        while(cnt--)
        {
            cout << "I am father, pid: " << getpid() << endl;
            sleep(1);
        }

        int status =0;
        while(true)
        {
            pid_t ret = waitpid(id, &status, WNOHANG);
            if(ret > 0)
            {
                cout << "wait success..." << endl;
                
                if(WIFEXITED(status))
                {
                    //正常退出
                    cout << "process is already done nomal" << endl;
                }
                else
                {
                    //异常退出
                    cout << "process has exception" << endl;
                }

                break;
            }
            else if(ret < 0)
            {
                cout << "wait failed..." << endl;
                break; 
            }
            else
            {
                //这里是使用非阻塞轮询, 父进程在这里可以干其他的事情不用阻塞住
                //父进程在进程等待的时候可以以非阻塞的方式也执行其他的任务
                ExcuteTask();
            }
        }
    }
    
    return 0;
}

